1 00:00:00,750 --> 00:00:01,320 Hey there. 2 00:00:01,320 --> 00:00:02,190 Welcome back. 3 00:00:02,190 --> 00:00:07,170 We're going to continue where we left off with our zombie eye by adding more features like playing different 4 00:00:07,170 --> 00:00:12,990 sound effects for zombie, having our zombie wander around the map, and implementing health regeneration. 5 00:00:14,370 --> 00:00:16,530 Back inside of our zombie AI script. 6 00:00:16,530 --> 00:00:21,870 What we want to be able to do is we want to create a function to allow us to have our zombie wander 7 00:00:21,870 --> 00:00:27,600 around the map when we were not able to generate a path, or we don't have any players nearby to Pathfind 8 00:00:27,600 --> 00:00:28,320 towards. 9 00:00:29,100 --> 00:00:34,530 In these two scenarios, we need to make sure we set the walk speed of our humanoid back to the property's 10 00:00:34,680 --> 00:00:39,960 wandering speed, and then we can have a function, something like wander, call it, and have our zombie 11 00:00:39,960 --> 00:00:41,550 wander around the map. 12 00:00:42,230 --> 00:00:45,290 So we can go up and create a new function. 13 00:00:47,650 --> 00:00:50,920 I will call this function wander. 14 00:00:51,460 --> 00:00:58,120 And inside of here, what we need to do is we actually want to keep track of a boolean to tell us whether 15 00:00:58,120 --> 00:01:00,250 or not the zombie is currently wandering. 16 00:01:00,250 --> 00:01:05,440 And that's because if the zombie is in the wandering state, but then they get shot. 17 00:01:05,440 --> 00:01:11,020 We want to set wandering back to false and that will tell the wandering function hey, we've been shot. 18 00:01:11,020 --> 00:01:17,440 We need to get out and start pathfinding and find the nearest player to us so we can go ahead and create 19 00:01:17,440 --> 00:01:18,610 another boolean. 20 00:01:18,730 --> 00:01:22,150 I'm going to call this wandering and I'm going to set it to false by default. 21 00:01:22,150 --> 00:01:26,860 However, when we start to wander, we could go ahead and set wandering equal to true. 22 00:01:26,860 --> 00:01:30,070 So inside of the wander function we'll set wandering equal to true. 23 00:01:31,370 --> 00:01:37,520 And then we'll basically just generate a random position for our eye to wander towards. 24 00:01:37,520 --> 00:01:40,850 So let's go ahead and also get a random data type. 25 00:01:41,210 --> 00:01:42,080 We'll just call it RNG. 26 00:01:42,080 --> 00:01:43,760 And that's equal to random dot new. 27 00:01:44,630 --> 00:01:46,190 And then we can go down. 28 00:01:46,790 --> 00:01:50,030 And we can generate a random x and z position in the world. 29 00:01:50,030 --> 00:01:54,410 So I'll call this random x and that will be equal to RNG next integer. 30 00:01:54,410 --> 00:01:57,350 And we'll do anywhere between -12 to 12. 31 00:01:57,560 --> 00:02:01,550 And then we can copy this to the exact same thing for the z axis. 32 00:02:03,340 --> 00:02:06,070 And then we can go ahead and just make a new goal position. 33 00:02:06,070 --> 00:02:09,370 I'll just call it goal and it's going to be equal to my root part. 34 00:02:10,230 --> 00:02:11,430 Dot position. 35 00:02:11,430 --> 00:02:16,920 And then we're going to add a new vector three with this random x zero on the y. 36 00:02:16,920 --> 00:02:18,690 And then this random z. 37 00:02:20,860 --> 00:02:23,620 Then we can basically do the exact same thing that we've done in here. 38 00:02:23,620 --> 00:02:25,390 We'll compute a new path. 39 00:02:25,570 --> 00:02:29,590 This time the goal is going to be our goal. 40 00:02:29,830 --> 00:02:32,200 And then we'll compute this new path. 41 00:02:32,470 --> 00:02:37,390 And then if we were not successful in generating this path, then we're basically just going to return 42 00:02:37,390 --> 00:02:38,200 out of this function. 43 00:02:38,200 --> 00:02:45,010 So path dot status is not equal to the enum dot path status of success. 44 00:02:45,010 --> 00:02:47,080 Then we'll just return out of this function. 45 00:02:47,080 --> 00:02:49,420 Check to see if there is any players nearby. 46 00:02:49,420 --> 00:02:52,660 And if there isn't, then we'll go back into the watering function. 47 00:02:52,660 --> 00:02:56,650 It'll generate a new position and we'll try to pathfind to that new position. 48 00:02:56,740 --> 00:03:01,720 Otherwise, if we were successful in generating the path, then we can of course loop through every 49 00:03:01,720 --> 00:03:03,520 single waypoint inside of our path. 50 00:03:03,520 --> 00:03:04,930 Get waypoints. 51 00:03:06,640 --> 00:03:10,870 And we'll have our humanoid move to that waypoint position. 52 00:03:15,380 --> 00:03:22,760 And then we can check if the waypoint action is equal to the enum dot pathway point action of jump, 53 00:03:22,760 --> 00:03:25,670 and if it is, we'll have our humanoid jump. 54 00:03:28,470 --> 00:03:29,070 Otherwise. 55 00:03:29,070 --> 00:03:34,620 Of course, we'll also wait for the move to finish event, but we're going to time out it as well. 56 00:03:34,620 --> 00:03:38,610 So timed out is going to be equal to wait. 57 00:03:38,610 --> 00:03:41,610 With time out we'll pass my humanoid. 58 00:03:43,320 --> 00:03:46,260 Dot moved to finish and then pass the number three. 59 00:03:46,260 --> 00:03:52,260 And if we timed out during this wandering phase, then we could also print in here something like zombie 60 00:03:52,260 --> 00:03:54,510 timed out while wandering. 61 00:03:55,470 --> 00:03:57,090 Is it stuck? 62 00:03:57,780 --> 00:04:00,840 And then we'll just force our humanoid to jump again. 63 00:04:00,840 --> 00:04:07,080 And then we'll just break out of this loop and try to generate a new point to Pathfind towards. 64 00:04:07,470 --> 00:04:14,610 Otherwise, this for loop is another good opportunity to see if, um, our wandering variable is not 65 00:04:14,610 --> 00:04:14,970 true. 66 00:04:14,970 --> 00:04:21,210 So if not wandering, then this would mean that we got shot by a player, because what we can go ahead 67 00:04:21,210 --> 00:04:26,910 and do is when we're listening for when the health of our zombie changes, when we set the targeting 68 00:04:26,910 --> 00:04:31,410 distance to the alert targeting distance, we can also go ahead and set wandering equal to false. 69 00:04:31,410 --> 00:04:37,650 And that way if we are wandering, it will notify when we are in this for loop that hey! 70 00:04:39,000 --> 00:04:46,290 We got shot, so we should go ahead and break out of this loop and check to see if there are any nearby 71 00:04:46,290 --> 00:04:48,270 players that we can pathfind towards. 72 00:04:48,300 --> 00:04:54,750 Otherwise, what we can go ahead and do is after we are done wandering, I want to have our zombie kind 73 00:04:54,750 --> 00:05:01,440 of stand still for a couple seconds before our zombie goes and starts wandering to a new waypoint. 74 00:05:01,470 --> 00:05:08,100 So after this for loop is over, if our wandering variable is still true, then we can go ahead and 75 00:05:08,100 --> 00:05:09,390 just yield randomly. 76 00:05:09,390 --> 00:05:14,070 We could do RNG next number and wait anywhere between 1 and 3 seconds. 77 00:05:14,400 --> 00:05:18,300 And then once that time is up then we'll check to see if there's any nearby players. 78 00:05:18,300 --> 00:05:23,130 And if there isn't, we'll go back into our wandering phase and start wandering around the map again. 79 00:05:24,190 --> 00:05:29,170 Now, this is also a good opportunity for us to implement all of the different sound IDs inside of our 80 00:05:29,170 --> 00:05:36,160 properties, such as attacking the death sound when we see a player, or just random growling sounds. 81 00:05:37,290 --> 00:05:44,880 So we can go ahead and create a function to basically pick an ID randomly out of these arrays we're 82 00:05:44,880 --> 00:05:50,040 going to be using, and then play that sound on the head of our zombie. 83 00:05:50,040 --> 00:05:53,310 So we'll call this function play random sound. 84 00:05:53,550 --> 00:05:56,130 We'll get passed an ID list. 85 00:05:56,130 --> 00:05:59,340 And then the parent we would like to set the sound to. 86 00:05:59,670 --> 00:06:02,010 And then we'll make a new sound instance. 87 00:06:04,130 --> 00:06:07,610 We'll make sure we'll set the sound ID equal to. 88 00:06:07,610 --> 00:06:12,470 And inside of this ID list we're going to randomly grab an ID out of there. 89 00:06:12,470 --> 00:06:16,130 So one to the max number of elements in the table. 90 00:06:16,870 --> 00:06:21,640 And then we'll make sure to loop through every single property and value inside of our properties. 91 00:06:21,850 --> 00:06:25,840 Sound properties and apply that on our sound. 92 00:06:28,550 --> 00:06:33,410 And then we can go ahead and set the parent of our sound equal to the parent pass to the function. 93 00:06:33,410 --> 00:06:34,880 We'll play that sound. 94 00:06:34,880 --> 00:06:39,770 And then when that sound ends, we'll make sure to destroy it and clean it up. 95 00:06:41,290 --> 00:06:44,320 So now we can go ahead and just start playing random sounds. 96 00:06:44,320 --> 00:06:46,990 For example, when we are wandering around the map. 97 00:06:46,990 --> 00:06:52,420 So through each iteration of our for loop we can have an if statement check to see. 98 00:06:52,420 --> 00:06:59,800 For example, let's say we have a 10% chance through each iteration of this loop to play a random growling 99 00:06:59,800 --> 00:07:00,160 sound. 100 00:07:00,160 --> 00:07:02,710 So what we can do is we can generate a random number. 101 00:07:02,710 --> 00:07:05,620 So rng next integer 1 to 10. 102 00:07:05,740 --> 00:07:10,690 And if this value is equal to one then we'll play a random growling sound. 103 00:07:10,690 --> 00:07:13,810 So we could do properties dot growl sound ids. 104 00:07:13,810 --> 00:07:16,600 And the parent is going to be the head of our zombie. 105 00:07:17,340 --> 00:07:22,020 And then we can just copy this and kind of do this in several other areas. 106 00:07:22,990 --> 00:07:28,000 For example, when we were computing a path and we're chasing after a player. 107 00:07:28,390 --> 00:07:33,910 If we are, let's say, repeatedly running towards a player, we could also randomly play a growling 108 00:07:33,910 --> 00:07:40,330 sound so we could just, you know, paste that same kind of if statement in here and we'll just play 109 00:07:40,330 --> 00:07:41,680 a random growling sound. 110 00:07:41,680 --> 00:07:46,630 However, we do need to note that this repeat loop is executing much faster than that for loop. 111 00:07:46,630 --> 00:07:49,060 So let's go ahead and decrease the odds a bit. 112 00:07:49,060 --> 00:07:53,050 And we could set 10 to 150 instead. 113 00:07:53,050 --> 00:07:57,430 So we have a smaller chance to play a random growling sound. 114 00:07:58,250 --> 00:08:00,140 And then we can do the exact same thing. 115 00:08:00,140 --> 00:08:06,020 For example, in our get nearest player function, we had those player scene sound IDs. 116 00:08:06,020 --> 00:08:15,020 So what we can do is if we got a closest target, then we'll just paste this in here and randomly play 117 00:08:15,020 --> 00:08:19,220 one of the player scene sound IDs. 118 00:08:20,810 --> 00:08:22,790 And then we can use the same function. 119 00:08:22,790 --> 00:08:26,990 When our zombie dies, we can play one of the death sounds. 120 00:08:26,990 --> 00:08:34,220 So when our zombie dies, we'll call play random sound and we'll pass properties dot death sound IDs, 121 00:08:34,220 --> 00:08:36,410 and we'll play that on the head of the zombie. 122 00:08:37,680 --> 00:08:43,920 And then another thing we want to make sure we do is that when we are wandering after we break out of 123 00:08:43,920 --> 00:08:49,080 this wandering function, we want to make sure we go ahead and set wandering back to false because we 124 00:08:49,080 --> 00:08:50,250 are no longer wandering. 125 00:08:50,250 --> 00:08:54,420 And I'll make sure to copy this and put this in both of these sections. 126 00:08:55,140 --> 00:08:59,670 And another important thing we want to implement is the ability for our zombie to attack a player. 127 00:08:59,970 --> 00:09:07,680 So inside of our compute path to function, when we see a humanoid and we're running directly after 128 00:09:07,680 --> 00:09:11,040 them, we should be able to also like call a function here. 129 00:09:11,040 --> 00:09:16,380 We could call it like attack and basically attack a player, check to see if they're close enough, 130 00:09:16,380 --> 00:09:21,330 and if the zombie is close enough and within range to attack the player, then we'll deal damage to 131 00:09:21,330 --> 00:09:25,350 them so we can have a function where we pass the target to it. 132 00:09:25,650 --> 00:09:28,770 And then I'll go up and make a new attack function. 133 00:09:31,120 --> 00:09:37,330 And then we basically want to make sure we have a cooldown to determine when we are able to attack. 134 00:09:37,330 --> 00:09:44,740 Because if you remember in our properties table, we set a cooldown between attack property. 135 00:09:45,130 --> 00:09:51,700 So what I'm going to do is I'm going to create another boolean and I'm going to call this one Can Attack. 136 00:09:52,730 --> 00:09:55,010 I'm going to set this to true by default. 137 00:09:55,620 --> 00:09:58,410 And then we could go back down to our attack function. 138 00:09:58,410 --> 00:10:01,620 And inside of our attack function, we want to check whether or not we can actually attack. 139 00:10:01,620 --> 00:10:05,130 So if we cannot attack, then we're just going to return out of this function. 140 00:10:05,490 --> 00:10:10,170 Another thing we need to verify is if we are within range to attack our player. 141 00:10:10,500 --> 00:10:15,540 So if my root part dot position subtracted by the target's position. 142 00:10:16,740 --> 00:10:21,810 And then get the magnitude of that and see if that is greater than our properties. 143 00:10:21,810 --> 00:10:22,710 Dot. 144 00:10:23,470 --> 00:10:28,600 Attack range, then clearly we are not within range to attack this player, so we're just going to return. 145 00:10:28,780 --> 00:10:31,630 Otherwise we're going to set can attack equal to false. 146 00:10:32,670 --> 00:10:38,880 And then we're going to refer to our target parent, get the humanoid of that player, and then use 147 00:10:38,880 --> 00:10:41,730 the take damage function to deal some damage. 148 00:10:41,730 --> 00:10:43,800 And that's going to be equal to our properties. 149 00:10:43,800 --> 00:10:45,840 Dot damage per hit. 150 00:10:47,150 --> 00:10:52,220 And then since we don't want this function to yield, we're just going to delay a function in a new 151 00:10:52,220 --> 00:10:53,210 thread instead. 152 00:10:53,210 --> 00:10:57,350 And we're going to delay it for the properties dot cooldown between attack. 153 00:10:58,600 --> 00:11:02,890 And then inside of this function, we can just simply set can attack back to true. 154 00:11:04,010 --> 00:11:07,370 We could also do the same thing of playing a random sound. 155 00:11:07,370 --> 00:11:14,660 So inside of here, let's say we had a one out of four chance or 25% chance to play one of the attack 156 00:11:14,660 --> 00:11:16,790 sound IDs, so we'll do something like that. 157 00:11:18,030 --> 00:11:23,670 So now our zombie should have the ability to wander around the map as well as attack our player and 158 00:11:23,670 --> 00:11:28,260 play random sounds while he is wandering, or while he's attacking, or when he dies. 159 00:11:28,290 --> 00:11:34,680 So what we can go ahead and do is we can run our game instead to go ahead and see our zombie in action. 160 00:11:35,430 --> 00:11:37,800 And as you can see, it says our zombie is wandering. 161 00:11:37,800 --> 00:11:41,730 And he paused in place and now he's wandering to a new position. 162 00:11:42,000 --> 00:11:45,660 And if you heard, he randomly played a sound. 163 00:11:45,960 --> 00:11:46,260 There you go. 164 00:11:46,260 --> 00:11:47,370 He played another one. 165 00:11:49,160 --> 00:11:53,810 Now our zombie seems a lot more lively since he's playing these different sounds and he's just kind 166 00:11:53,810 --> 00:11:57,020 of slowly wandering around our map, which is kind of cool. 167 00:11:58,070 --> 00:12:01,910 Now let me go ahead and move my zombie all the way. 168 00:12:02,390 --> 00:12:05,780 Um, let's say we put them all the way inside of here. 169 00:12:07,610 --> 00:12:10,130 And what we're going to go ahead and do. 170 00:12:10,840 --> 00:12:15,340 Is we're going to spawn the player into the map with a weapon, and we're going to see if we can shoot 171 00:12:15,340 --> 00:12:19,690 our zombie and see if that increases the targeting distance for the zombie. 172 00:12:21,580 --> 00:12:24,550 So I'm going to go into server storage. 173 00:12:25,780 --> 00:12:29,620 I'm just going to copy one of these guns, like the assault rifle, put it in my starter pack, and 174 00:12:29,620 --> 00:12:31,480 then I'm going to playtest my game. 175 00:12:34,770 --> 00:12:37,680 And hopefully my zombie stays wandering. 176 00:12:37,710 --> 00:12:42,960 So now that I'm on the map, great, it still says my zombie is wandering around. 177 00:12:42,960 --> 00:12:47,100 Let me see if I can actually highlight him in the workspace. 178 00:12:47,160 --> 00:12:49,740 So my zombie is over there wandering around. 179 00:12:49,740 --> 00:12:50,610 Very cool. 180 00:12:51,000 --> 00:12:55,650 Let me see if I can get a vantage point to kind of shoot him from far away. 181 00:12:55,650 --> 00:12:59,460 So if I stand up here, let me see if I'm able to shoot him. 182 00:13:03,150 --> 00:13:04,980 If I can get a good vantage point. 183 00:13:07,550 --> 00:13:07,880 There we go. 184 00:13:07,880 --> 00:13:09,320 I hit him a couple times. 185 00:13:14,990 --> 00:13:18,770 And I don't know if it increased his wandering distance. 186 00:13:18,770 --> 00:13:21,830 Oh, it definitely did because he is now coming after us. 187 00:13:23,290 --> 00:13:28,060 So after we shot him, he definitely increased the range of his wandering distance. 188 00:13:28,060 --> 00:13:33,070 And now he is coming to get us and he can see us and he's starting to run towards us. 189 00:13:34,210 --> 00:13:39,760 Now you can see that there is a bit of a problem here, and that our zombie is not jumping when he encounters 190 00:13:39,760 --> 00:13:41,200 these obstacles. 191 00:13:41,740 --> 00:13:49,720 So that means we need to basically listen, um, one fix we could do for it is we could listen for when 192 00:13:49,720 --> 00:13:54,400 his lower torso touches something, and when his lower torso touches something, we can force him to 193 00:13:54,400 --> 00:13:57,310 jump, and that will allow him to jump over obstacles. 194 00:13:57,310 --> 00:14:01,840 But as it stands at the moment, he is not able to jump over these obstacles. 195 00:14:02,170 --> 00:14:04,330 But let's go ahead and see if he is able to hurt us. 196 00:14:04,330 --> 00:14:07,420 So if I stand next to him, as you can see, he just herded me. 197 00:14:08,380 --> 00:14:09,610 And he's hurting me again. 198 00:14:09,610 --> 00:14:13,630 So as you can see, our zombie is very nice, very cool. 199 00:14:14,080 --> 00:14:16,570 And you can hear him playing the attack sounds as well. 200 00:14:16,570 --> 00:14:18,040 Let me see if he plays another one. 201 00:14:21,020 --> 00:14:22,400 Come on, buddy, play it for me. 202 00:14:25,200 --> 00:14:25,950 Ah. 203 00:14:28,050 --> 00:14:29,250 Yeah, there we go. 204 00:14:29,250 --> 00:14:30,150 He played one of the attack. 205 00:14:30,150 --> 00:14:31,200 Sounds very cool. 206 00:14:31,680 --> 00:14:37,200 And then if we kill our zombie, he should play the death sound and then get cleaned up off the map. 207 00:14:37,200 --> 00:14:38,220 So let's go ahead and kill him. 208 00:14:39,120 --> 00:14:39,690 There we go. 209 00:14:39,690 --> 00:14:43,500 He played his death sound, and then he should get cleaned up. 210 00:14:43,500 --> 00:14:44,010 There you go. 211 00:14:44,010 --> 00:14:45,750 He cleaned himself off the map. 212 00:14:45,750 --> 00:14:51,270 And you could also see that this print statement printed within our server script as well, it says 213 00:14:51,270 --> 00:14:53,820 I am dead or can't see the player or the player is dead. 214 00:14:53,910 --> 00:15:01,140 So while he was chasing after us through the next iteration of that repeat loop, he realized that his 215 00:15:01,140 --> 00:15:02,850 alive variable is set to false. 216 00:15:02,850 --> 00:15:04,170 So he's like, yep, I'm dead. 217 00:15:04,170 --> 00:15:05,100 I'm going to break. 218 00:15:05,100 --> 00:15:06,900 I'm going to stop pathfinding. 219 00:15:06,900 --> 00:15:08,640 And then it goes back to the while loop. 220 00:15:08,640 --> 00:15:13,110 The while loop goes to the next iteration, but it also sees that the alive variable is set to false. 221 00:15:13,110 --> 00:15:14,760 So it just stops executing. 222 00:15:14,760 --> 00:15:19,680 And the main thread of execution reaches the end of this script and there's nothing to execute anymore. 223 00:15:20,690 --> 00:15:25,220 So now what we can go ahead and do is allow our zombie to jump when his lower torso touches something, 224 00:15:25,220 --> 00:15:30,440 as well as implementing the health regeneration for a zombie. 225 00:15:30,440 --> 00:15:33,560 And let's go ahead and do that in a separate script. 226 00:15:33,560 --> 00:15:38,000 So inside of our zombie we can go ahead and create a new script. 227 00:15:38,000 --> 00:15:42,590 And I'm going to call this my property listeners. 228 00:15:44,350 --> 00:15:47,350 Inside of here, I'm going to be using the same common template. 229 00:15:48,550 --> 00:15:54,130 And I'm going to go ahead and make a reference to the properties of my zombie. 230 00:15:54,130 --> 00:15:58,420 So that'll be require script dot parent dot properties. 231 00:15:58,420 --> 00:16:01,510 And I'm also going to get the humanoid for my zombie. 232 00:16:01,540 --> 00:16:05,170 So we'll do script dot parent dot humanoid. 233 00:16:05,170 --> 00:16:08,710 And then we'll get a random data type as well. 234 00:16:09,960 --> 00:16:14,490 And that's because we're also going to listen in here for when our humanoid dies. 235 00:16:14,490 --> 00:16:20,940 And then we're going to award a random amount of money to our players based on that money drop property 236 00:16:20,940 --> 00:16:22,080 we have right here. 237 00:16:22,600 --> 00:16:28,300 So inside of here, inside of the handler section, what I want to check is first I want to check if 238 00:16:28,330 --> 00:16:33,220 inside of our agent params that we have, the agent can jump property set to true. 239 00:16:33,220 --> 00:16:38,350 If it is set to true, then we're okay to listen for when our lower torso is touched to go ahead and 240 00:16:38,350 --> 00:16:39,760 force the zombie to jump. 241 00:16:39,760 --> 00:16:44,680 If we've explicitly set that the zombie cannot jump, then I don't want the zombie to ever jump. 242 00:16:45,430 --> 00:16:50,230 So what I'm going to do is actually I'll make another variable for my zombie, which is script dot parent. 243 00:16:50,230 --> 00:16:53,920 And then that way I can go ahead and replace these references with my zombie. 244 00:16:54,800 --> 00:17:01,550 And then we can go ahead and listen for when the zombie dot lower torso is touched. 245 00:17:01,670 --> 00:17:06,530 And when it is touched, we can go ahead and force the zombie to jump. 246 00:17:06,800 --> 00:17:14,750 Now I only want the zombie to jump if the thing that touched his torso did not belong to a character 247 00:17:14,750 --> 00:17:18,650 model, so he didn't touch another zombie, or he didn't touch a player's character model. 248 00:17:18,650 --> 00:17:23,540 And I also want to make sure the part that he touched didn't have can collide enabled. 249 00:17:23,540 --> 00:17:28,370 So, for example, when our zombie is walking through invisible walls like this one, the can touch 250 00:17:28,370 --> 00:17:33,260 event is still going to fire, which means he's going to jump even though this is a non collidable transparent 251 00:17:33,260 --> 00:17:33,860 part. 252 00:17:34,520 --> 00:17:36,140 So what we can go ahead and do. 253 00:17:36,830 --> 00:17:42,620 Is, we can check if the part that touched the lower torso of our zombie. 254 00:17:43,100 --> 00:17:47,150 If the parent find first child, which is a humanoid. 255 00:17:47,150 --> 00:17:56,150 So if it belongs to a character model or let's say that can collide is disabled for this part. 256 00:17:56,150 --> 00:18:00,440 So if it's not collidable, then we're just going to return and not force our zombie to jump. 257 00:18:01,230 --> 00:18:07,170 The next thing we want to listen for is if we have the regenerates health property set to true. 258 00:18:07,200 --> 00:18:13,110 If we do, then we want to listen for when the health changed event on our humanoid fires, we'll connect 259 00:18:13,110 --> 00:18:14,010 a function. 260 00:18:15,470 --> 00:18:20,300 And what we want to go ahead and do is we want to create a debounce. 261 00:18:20,300 --> 00:18:24,620 So we want to store in a variable if we are already healing our zombie. 262 00:18:24,620 --> 00:18:27,440 So we'll set healing equal to false. 263 00:18:27,440 --> 00:18:31,370 And then inside of here, if we're already healing we'll return. 264 00:18:31,370 --> 00:18:33,770 Otherwise we're going to set healing equal to true. 265 00:18:34,530 --> 00:18:40,710 And actually, before we set healing equal to true, we also want to make sure if our humanoid dot health. 266 00:18:42,110 --> 00:18:51,800 Is less than or equal to my humanoid max health, and we multiply that by the properties dot and I believe 267 00:18:51,800 --> 00:18:53,480 it was called what was it called? 268 00:18:53,480 --> 00:18:54,920 Health regen limit. 269 00:18:54,920 --> 00:18:57,740 So we'll do the health regen limit. 270 00:19:00,200 --> 00:19:05,540 So if our health is greater than or equal to the health region limit, then that means we can't regenerate 271 00:19:05,540 --> 00:19:08,090 any health and we're just going to return. 272 00:19:08,210 --> 00:19:14,000 Otherwise, if our health is below that limit and then we can have a repeat loop repeatedly increase 273 00:19:14,000 --> 00:19:21,680 the health of our humanoid until our humanoid reaches that health limit, or our humanoid is dead. 274 00:19:21,740 --> 00:19:28,430 So we'll do my humanoid dot health plus equal the properties dot health regen amount. 275 00:19:28,430 --> 00:19:32,510 And then we're going to yield for our properties dot health region tick. 276 00:19:33,320 --> 00:19:38,720 And then we're going to keep healing our humanoid until my humanoid dot health is greater than or equal 277 00:19:38,720 --> 00:19:47,660 to my humanoid dot max health multiplied by the properties dot healing or health region limit. 278 00:19:48,430 --> 00:19:53,440 Or if my humanoid dot health is less than or equal to zero. 279 00:19:55,070 --> 00:19:59,720 And then once we're out of that repeat loop, we can go ahead and set healing equal to false. 280 00:20:01,500 --> 00:20:05,070 Now, the last thing we want to go ahead and listen for is when our humanoid dies. 281 00:20:05,070 --> 00:20:09,210 So my humanoid will listen to the died event and we'll connect a function. 282 00:20:09,210 --> 00:20:13,380 We want to check to see if the cause of death for this humanoid was a player. 283 00:20:13,380 --> 00:20:19,740 So we're going to see if there is anything within the who last damaged object value inside of our zombie. 284 00:20:19,740 --> 00:20:25,710 So I'll create a variable called player, and it's going to be equal to my zombie Dot who last damaged 285 00:20:25,710 --> 00:20:27,540 and get the value inside of there. 286 00:20:27,540 --> 00:20:31,800 If there is no value inside of that object value, then we're just going to return. 287 00:20:32,100 --> 00:20:37,380 And then I'm just going to double check to make sure that the value stored in our object value actually 288 00:20:37,380 --> 00:20:38,550 belongs to a player. 289 00:20:38,550 --> 00:20:46,350 So if this player is not actually a player instance for some reason, then we're also going to return. 290 00:20:46,500 --> 00:20:52,560 Otherwise what we can go ahead and do is we can increment that kills value within the player's leader 291 00:20:52,560 --> 00:20:52,980 stats. 292 00:20:52,980 --> 00:20:55,710 So kills dot value plus equal one. 293 00:20:55,710 --> 00:20:58,320 And then we can also give our player some money. 294 00:20:58,320 --> 00:21:02,370 So player dot leader stats dot money dot value. 295 00:21:02,370 --> 00:21:05,970 And we're going to increment it by and we're going to use RNG next integer. 296 00:21:06,150 --> 00:21:12,240 And pick a random value between the properties dot money drop dot minimum and properties dot money drop 297 00:21:12,240 --> 00:21:13,350 dot maximum. 298 00:21:14,240 --> 00:21:19,880 So now our zombies should be able to jump when we've defined in the properties that it can jump, our 299 00:21:19,880 --> 00:21:21,680 zombies should be able to regenerate health. 300 00:21:21,770 --> 00:21:27,410 When we've defined that, it can regenerate health, and our zombie should accredit a kill and money 301 00:21:27,410 --> 00:21:28,910 to a player that killed it. 302 00:21:29,060 --> 00:21:31,010 So let's go ahead and test this all out. 303 00:21:32,430 --> 00:21:34,140 My zombie should still be up. 304 00:21:34,140 --> 00:21:35,160 He's still back there. 305 00:21:35,160 --> 00:21:37,350 And if I go and play test my game. 306 00:21:39,590 --> 00:21:41,990 Currently my zombie is wandering, which is cool. 307 00:21:42,020 --> 00:21:43,490 I'll spawn into the map. 308 00:21:44,650 --> 00:21:49,900 And then I'll show you that actually his wandering or targeting radius increased because you remember 309 00:21:49,900 --> 00:21:51,250 he was back inside of there. 310 00:21:51,250 --> 00:21:54,520 And when I was standing right here, he was starting to pathfind towards us. 311 00:21:54,520 --> 00:22:00,130 But as you can see, I'm standing in the same area and our zombie is not pathfinding towards us because 312 00:22:00,130 --> 00:22:01,900 his radius has not increased. 313 00:22:01,900 --> 00:22:05,980 But if I were to shoot him, let me go ahead and find my zombie. 314 00:22:05,980 --> 00:22:07,240 He's back there somewhere. 315 00:22:07,950 --> 00:22:12,930 So if I were to pull out my gun and let me see if I can get a shot on him. 316 00:22:15,620 --> 00:22:17,360 Make it a little bit closer. 317 00:22:18,890 --> 00:22:23,240 Hey, still isn't pathfinding towards us, but if I get a shot on him. 318 00:22:24,800 --> 00:22:26,090 Okay, I got a shot on him. 319 00:22:26,480 --> 00:22:32,240 As you can see, his targeting radius increased and now he is coming to Pathfind towards us. 320 00:22:32,240 --> 00:22:34,190 And you can see each path. 321 00:22:34,550 --> 00:22:36,530 And as he is pathfinding. 322 00:22:37,420 --> 00:22:43,300 His pathfinding goes beyond 20 studs, and he goes and generates a new path to follow me to. 323 00:22:43,570 --> 00:22:45,100 As you can see, here he is pathfinding. 324 00:22:45,100 --> 00:22:48,760 And eventually he sees us and he's chasing after us. 325 00:22:50,620 --> 00:22:50,920 Is he? 326 00:22:50,920 --> 00:22:52,000 Is he screaming? 327 00:22:53,020 --> 00:22:53,410 Yep. 328 00:22:53,410 --> 00:22:53,890 There we go. 329 00:22:53,890 --> 00:22:55,870 He's he wants to eat us. 330 00:22:56,200 --> 00:22:59,620 And if I go yep. 331 00:22:59,620 --> 00:23:02,230 If I touch him or get close to him, he starts hurting me. 332 00:23:05,850 --> 00:23:07,110 It continues to hurt me. 333 00:23:07,800 --> 00:23:11,040 And if I get his health below, let's say half health. 334 00:23:11,190 --> 00:23:12,480 So let me get him down low. 335 00:23:13,080 --> 00:23:14,430 Oh, man, I accidentally killed them. 336 00:23:14,430 --> 00:23:15,120 Oops. 337 00:23:15,120 --> 00:23:19,890 Let's go ahead and play test again and try to get him below half health. 338 00:23:21,170 --> 00:23:22,910 Is pathfinding to us. 339 00:23:23,730 --> 00:23:25,770 And then actually let me get a headshot on him. 340 00:23:27,210 --> 00:23:28,920 Okay, he's below half health. 341 00:23:28,920 --> 00:23:31,260 He should start regenerating health. 342 00:23:31,260 --> 00:23:35,430 And as you can see, if you look, his health is slowly starting to increase. 343 00:23:35,430 --> 00:23:37,830 And then when he hits the halfway mark in his health. 344 00:23:38,160 --> 00:23:38,580 Yep. 345 00:23:38,580 --> 00:23:41,640 As you can see, he's no longer regenerating any health anymore. 346 00:23:41,640 --> 00:23:42,570 Very cool. 347 00:23:42,840 --> 00:23:47,730 You can also see that he jumped when he hit that, uh, barrier right there. 348 00:23:47,940 --> 00:23:50,280 So if I walk on the other side of this barrier. 349 00:23:51,860 --> 00:23:57,080 As you can see, it is forcing him to jump because that barrier is touching his lower torso. 350 00:23:57,560 --> 00:23:59,240 But if I stand there, you go. 351 00:23:59,240 --> 00:24:02,570 As you can see, he jumps over the sandbag barrier. 352 00:24:04,060 --> 00:24:06,310 Because it's touching his lower torso. 353 00:24:07,090 --> 00:24:08,950 It's continuing to pathfind towards us. 354 00:24:08,950 --> 00:24:13,390 Then eventually if we go around this vehicle, he's going to generate a new path to come to us. 355 00:24:14,560 --> 00:24:15,580 And he's coming around. 356 00:24:15,580 --> 00:24:17,770 He's coming around generating his path. 357 00:24:17,770 --> 00:24:19,450 And then eventually he sees us again. 358 00:24:20,730 --> 00:24:23,700 And then he touched that barrier and it forced him to jump up. 359 00:24:23,730 --> 00:24:24,540 Touches that. 360 00:24:24,540 --> 00:24:25,860 It forces him to jump. 361 00:24:26,360 --> 00:24:28,880 And he's continuing to come after us. 362 00:24:28,880 --> 00:24:35,180 And if we shoot him and kill him, as you can see, it incremented our kills and it gave us some money 363 00:24:35,180 --> 00:24:36,050 from him. 364 00:24:36,050 --> 00:24:36,860 Very cool. 365 00:24:38,000 --> 00:24:43,670 I'm going to go ahead and comment out the section of code where we're generating parts for the zombies 366 00:24:43,670 --> 00:24:44,090 path. 367 00:24:44,090 --> 00:24:50,120 So let me just comment all of that out, and then let's go ahead and playtest our game one last time 368 00:24:50,120 --> 00:24:53,900 just to make sure our zombie is working okay. 369 00:24:55,770 --> 00:24:59,400 We go to our zombie or run over here. 370 00:25:03,360 --> 00:25:04,200 Let's see. 371 00:25:04,200 --> 00:25:05,610 As you can see, he's running after us. 372 00:25:05,610 --> 00:25:06,690 He's running after us. 373 00:25:06,690 --> 00:25:08,010 He wants to eat us. 374 00:25:08,750 --> 00:25:13,850 If I go hide behind here, he's going to start pathfinding around when actually, as you can see, his 375 00:25:13,850 --> 00:25:16,910 pathfinding is no longer laggy, which is kind of interesting. 376 00:25:19,150 --> 00:25:22,450 I think it's just because I'm recording at the same time. 377 00:25:22,450 --> 00:25:25,270 But as you can see, his pathfinding isn't lagging right now. 378 00:25:25,270 --> 00:25:27,310 And then he sees me and he's coming after me. 379 00:25:28,330 --> 00:25:29,590 He's damaging me. 380 00:25:32,630 --> 00:25:35,990 Then if he touches the sandbag, there you go. 381 00:25:35,990 --> 00:25:37,250 It forces him to jump. 382 00:25:37,250 --> 00:25:41,900 Or if I come up here, as you can see, his pathfinding and jumping towards me. 383 00:25:41,900 --> 00:25:47,180 And even if I were to go and climb up onto this, uh, fountain right here, he's still going to pathfind 384 00:25:47,210 --> 00:25:48,470 towards me and get to me. 385 00:25:49,010 --> 00:25:52,970 So as you can see, he's generating his path and boom, he got to me and he's attacking me. 386 00:25:52,970 --> 00:25:53,840 Very cool. 387 00:25:54,560 --> 00:25:55,910 Then I'm going to run away. 388 00:25:55,910 --> 00:25:59,210 And he sees me and he's coming after me, and I'm going to go around here. 389 00:25:59,210 --> 00:26:02,570 And now he's generating a path to come towards to me. 390 00:26:04,440 --> 00:26:04,800 There you go. 391 00:26:04,800 --> 00:26:06,900 He found me and he's coming after me again. 392 00:26:06,900 --> 00:26:08,820 And he ain't going to stop until I kill him. 393 00:26:10,520 --> 00:26:11,060 Okay. 394 00:26:11,060 --> 00:26:14,870 We should have basically everything done with our zombie AI. 395 00:26:14,900 --> 00:26:22,220 I'm going to take a few minutes to copy the scripts and put them inside of my other zombies, and I'm 396 00:26:22,220 --> 00:26:27,740 going to modify this properties table for each one of the zombies inside of my game. 397 00:26:27,740 --> 00:26:32,480 So let me move all of these guys into the workspace so you can go ahead and take a look at every single 398 00:26:32,480 --> 00:26:36,740 one of them, and I'll move this guy back to where he belongs. 399 00:26:36,740 --> 00:26:39,890 So here's all the zombies that we're going to have in our game. 400 00:26:39,890 --> 00:26:45,980 And I'm going to go ahead and copy this module script and put it inside of each one of my zombies and 401 00:26:45,980 --> 00:26:50,450 give them all their own custom abilities and properties and stuff like that. 402 00:26:50,450 --> 00:26:53,660 And then I'll get back to you when I am finished doing that. 403 00:26:55,150 --> 00:27:00,040 Okay, so I've gone ahead and modified all of the different module scripts for each one of my zombies, 404 00:27:00,040 --> 00:27:05,920 and I also copied and pasted both the zombie I and the properties listeners scripts into each one of 405 00:27:05,920 --> 00:27:07,000 my zombies. 406 00:27:07,240 --> 00:27:12,040 And now that means every single one of these zombies here should be working, and they should be all 407 00:27:12,040 --> 00:27:18,010 their own unique zombies with their own unique speeds, their own unique health and stuff like that. 408 00:27:18,010 --> 00:27:24,640 So if we go and play test the game, all of these zombies should come running after me. 409 00:27:27,240 --> 00:27:29,820 As you can see, there's all of these zombies in our game. 410 00:27:29,850 --> 00:27:31,710 There's that one lightning zombie I made. 411 00:27:31,710 --> 00:27:33,570 He's very fast and he's coming after me. 412 00:27:33,570 --> 00:27:34,320 Let me get rid of him. 413 00:27:34,740 --> 00:27:36,540 But he doesn't have a lot of health. 414 00:27:36,570 --> 00:27:40,380 But as you can see, there's all the other zombies coming after me to attack me. 415 00:27:40,380 --> 00:27:44,070 I got some boss zombies here, including the sky would kill him. 416 00:27:45,060 --> 00:27:46,830 And then I also got this guy chasing after me. 417 00:27:46,830 --> 00:27:51,030 This is going to be like, the ultimate guy we're going to have at the last wave in our game. 418 00:27:51,030 --> 00:27:55,380 He has a lot of health, as you can see, so it's going to take a lot of bullets to kill this guy. 419 00:27:56,990 --> 00:28:02,960 But as you can see, each one of these zombies has their own unique health, their own unique style. 420 00:28:02,960 --> 00:28:06,470 For example, this is a slow zombie, but he does deal a lot more damage. 421 00:28:06,470 --> 00:28:09,290 And then there's some boss variants of each of the zombies. 422 00:28:10,430 --> 00:28:14,510 But as you can see, they're all chasing after me and they're all pathfinding to me. 423 00:28:14,510 --> 00:28:18,500 So as you can see, now that I'm hiding, all of them are generating their paths to come after me. 424 00:28:18,500 --> 00:28:20,990 And then once they see me, they're running after me. 425 00:28:21,020 --> 00:28:26,450 Let me see if I can try to get far enough away from these guys so they no longer chase after me. 426 00:28:28,150 --> 00:28:28,390 Okay. 427 00:28:28,390 --> 00:28:28,600 Yeah. 428 00:28:28,600 --> 00:28:33,730 So that guy back there lost interest in pathfinding after me because I got too far away. 429 00:28:33,730 --> 00:28:35,320 And as you can see. 430 00:28:36,100 --> 00:28:38,320 He's just randomly wandering around the map back there. 431 00:28:38,320 --> 00:28:40,660 He don't care about me anymore because I'm too far away. 432 00:28:40,810 --> 00:28:42,490 But now that I'm. 433 00:28:42,490 --> 00:28:46,780 Yeah, now that I'm in range, she's going to start pathfinding after me again, I believe. 434 00:28:46,990 --> 00:28:47,980 So let's go ahead and see. 435 00:28:47,980 --> 00:28:48,550 Yep. 436 00:28:48,760 --> 00:28:50,560 He's pathfinding to come after me. 437 00:28:50,560 --> 00:28:52,630 And then he sees me and now he's running after me. 438 00:28:52,630 --> 00:28:54,040 So very cool. 439 00:28:55,630 --> 00:29:01,630 If you would like to use these zombies with all of the variants that I've added to them with their configured 440 00:29:01,630 --> 00:29:07,360 properties, then I will have all of these zombies attached to the lecture for you to use in your game. 441 00:29:08,070 --> 00:29:12,030 Other than that, we should basically have everything done with our zombie AI. 442 00:29:12,060 --> 00:29:17,400 The only thing we have left to add are going to be the animations for our zombies, and we'll be doing 443 00:29:17,400 --> 00:29:20,190 that in the next lecture, so I'll see you there.